import { Message } from 'element-ui'

export default class SocketServe {
  static instance = null // 抛出这个实例之后 这个instance实例就相当于这个类的构造函数 可以调用里面的方法
  static get Instance () {
    if (!this.instance) {
      this.instance = new SocketServe()
    }
    return this.instance
  }

  ws = null // 和服务器连接的socket对象
  // /getDippingWSData
  connected = false // 标示是否连接成功
  timer = null
  sendRetryCount = 0 // 重新发送重试的次数 重启连接次数
  // connectRetryCount = 0 // 重新尝试的次数
  callBackMapping = {} // 存获取数据的回调函数

  heartCheck = {
    timeout: 3000, // 每隔三秒发送心跳
    severTimeout: 5000, // 服务端超时时间
    timeoutTimer: null,
    serverTimeoutTimer: null,
    start: function () {
      var that = this // 指向heartCheck对象
      this.timeoutTimer && clearTimeout(this.timeoutTimer)
      this.serverTimeoutTimer && clearTimeout(this.serverTimeoutTimer)
      this.timeoutTimer = setTimeout(() => {
        // 发送一个心跳
        this.ws.send('client heartBeating')
        that.serverTimeoutTimer = setTimeout(() => {
          console.log('检测不到心跳')
          Message({
            showClose: true,
            message: '服务器超过3秒没有回应了...',
            type: 'error'
          })
          this.ws.close() // 如果onclose会执行reconnect，我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
        }, that.severTimeout)
      }, that.timeout) // 执行三秒之后发现如果服务端回应心跳 就会再onmessage那里重新执行start方法继续发心跳 如果超过3秒没有回应 就会进行里面5秒的定时器 来关闭ws连接
    }
  }

  createWebSocket (urls) {
    if (!window.WebSocket) {
      Message({
        showClose: true,
        message: '当前浏览器不支持WebSocket',
        type: 'error'
      })
      return console.log('浏览器不支持WebSocket')
    }
    // console.log('this.ws之前的', this.ws)
    this.initConnect(urls)
  }

  initConnect (urls) {
    // 修改url 以后必tm不用这种
    console.log('urlsurls', urls)
    this.ws = new WebSocket(urls)
    // console.log('打开的时候', this.ws.readyState)
    this.ws.onopen = () => {
      console.log('连接服务端成功')
      this.connected = true
      // 心跳重置
      // this.heartCheck.start()
    }

    this.ws.onclose = (e) => { // 如果网络断开浏览器 服务器并没有触发onclose事件 避免服务器继续发送导致丢包
      // console.log('this.ws.readyState返回3', this.ws.readyState, e)
      // if (this.ws.readyState === 1) {
      //   console.log('this.ws.readyState返回', this.ws.readyState, this.ws)
      //   // this.reconnect()
      // } else {
      console.log('this.ws.readyState返回', this.ws, this.ws.readyState, e)
      if (this.ws.readyState === 3) {
        console.log('连接失败, 服务器可能关闭, 正在重连...') // 连接被关闭时触发
        // Message({
        //   showClose: true,
        //   message: '连接失败, 服务器可能关闭',
        //   type: 'error'
        // })
        this.connected = false
        this.createWebSocket(e.currentTarget.url)
      }
    }

    this.ws.onerror = () => {
      console.log('发生异常了')
      this.connected = false
      this.reconnect()
    }
    this.ws.onmessage = (msg) => {
      // 拿到任何消息都说明当前连接是正常的
      // if (JSON.parse(msg.data).heart === 'client heartBeating' || JSON.parse(msg.data).heart !== undefined) {
      // heartCheck.start()
      // } else {
      // console.log('msgmsg', msg)
      const datas = JSON.parse(msg.data)
      console.log('接收的数据', datas, this.ws)
      // console.log('this', this) // 这是SocketServe类 里面有ws对象
      if (this.callBackMapping.chartAllData) {
        this.callBackMapping.chartAllData.call(this, datas) // this指socket类 将datas作为chartAllData这个回调函数的参数来使用(别的组件调用registerCallBack 就将那个组件需要数据的函数拿过来)
        // this.callBackMapping[chartAllData].call(this, datas[chartAllData])
      }
    }
  }

  reconnect () {
    // 重连
    if (this.connected) {
      return // 如果连接着就不用重连
    } // 此时未连接 this.connected是false
    this.timer && clearTimeout(this.timer)
    this.timer = setTimeout(() => {
      this.initConnect()
    }, 5000)
  }

  // 获取回调的获取数据函数
  registerCallBack (chartAllData, callBack) { // callBack是getdata
    this.callBackMapping[chartAllData] = callBack// 把回调函数存储到callBackMapping里 都某个键里
  }

  // 取消某一个回调函数
  unRegisterCallBack (chartAllData) {
    this.callBackMapping[chartAllData] = null
  }

  // 前端自动断开
  routerLeaveClose () {
    this.ws.close()
    this.ws = null
    // this.ws.readyState = 3
    console.log('主动断开上一个', this.ws)
  }

  // 发送数据到服务端的
  sendData (data) {
    if (this.connected) {
      this.ws.send(JSON.stringify(data))
    } else {
      // 重连
      this.reconnect()
      this.sendData(data)
    }
  }
}
